package org.jground.rx.ui.zk;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.apache.commons.logging.Log;import org.apache.commons.logging.LogFactory;
import org.jground.rx.IRXObject;
import org.jground.rx.IRXObjectSynopsis;
import org.jground.rx.RXClass;
import org.jground.rx.RXView;
import org.jground.rx.ui.IUIAttributeView;
import org.jground.rx.ui.zk.viewControl.UIAttributeViewControlFactory;
import org.jground.util.CollectionUtils;
import org.jground.util.StringUtils;
import org.jground.zk.util.RXEventThreadInit;
import org.zkoss.zk.ui.Component;

public class UISynopsisRendererFactory {
    //
    //
    //
    private static Log logger = LogFactory.getLog(UISynopsisRendererFactory.class);

    //
    //
    // 
    private UIFrame uiFrame;
    // protected IRXObject rxDataObject;
    private Map<String, List<IUIAttributeView<Component,UIFrame>>> uiViewLists = new HashMap<String, List<IUIAttributeView<Component,UIFrame>>>();
    private Map<String, List<RXView>> rxViewLists = new HashMap<String, List<RXView>>();

    public UISynopsisRendererFactory(UIFrame uiFrame) {
        this.uiFrame = uiFrame;
        logger.debug("init");
    }

    private String createKey(String synopsisName, RXClass rxClass) {
        return synopsisName + "@" + rxClass;
    }

    private final static ThreadLocal<Set<String>> recursionProtector = new ThreadLocal<Set<String>>() {
        private HashSet<String> s;

        @Override
        protected Set<String> initialValue() {
            s = new HashSet<String>();
            return s;
        }
    };

    static {
        RXEventThreadInit.addInitClearTask(new Runnable() {
            public void run() {
                recursionProtector.get().clear();
            }
        });
    }

    public String toString(IRXObject rxd, String synopsisName) {
        return CollectionUtils.join(_render(rxd, synopsisName));
    }

    public String toString(IRXObject rxd) {
        return CollectionUtils.join(_render(rxd, ""));
    }

    public List<String> render(IRXObjectSynopsis rxd, String synopsisName) {
        return _render(rxd, synopsisName);
    }

    private List<String> _render(IRXObjectSynopsis rxSyn, String synopsisName) {
        IRXObject rxd = (IRXObject) rxSyn;
        String rsKey = rxd.getOid() + synopsisName;
        if (recursionProtector.get().contains(rsKey)) {
            return StringUtils.EMPTY_LIST;
        } else {
            recursionProtector.get().add(rsKey);
            try {
                RXClass rxClass = rxd.getRXClass();
                // rxClass.getSynopsisViews(synopsisName);
                String key = createKey(synopsisName, rxClass);

                List<IUIAttributeView<Component,UIFrame>> uiViewList = uiViewLists.get(key);
                List<RXView> rxViewList = rxViewLists.get(key);
                if (uiViewList == null) {
                    rxViewList = rxd.getRXClass().getSynopsis(synopsisName).getRXViews();
                    uiViewList = new ArrayList<IUIAttributeView<Component,UIFrame>>();
                    for (RXView rxView : rxViewList) {
                        IUIAttributeView<Component,UIFrame> uiview = UIAttributeViewControlFactory.create(uiFrame, rxView);
                        uiViewList.add(uiview);
                    }
                    rxViewLists.put(key, rxViewList);
                    uiViewLists.put(key, uiViewList);
                }
                ArrayList<String> renderValues = new ArrayList<String>(uiViewLists.size());
                for (int i = 0; i < rxViewList.size(); i++) {
                    RXView rxView = rxViewList.get(i);
                    IUIAttributeView<Component,UIFrame> uiView = uiViewList.get(i);
                    String attref = rxView.getAttref();
                    if (StringUtils.isNotBlank(attref)) {
                        String[] values = rxd.getValues(rxView.getAttref());
                        uiView.setDataContext(rxd);
                        uiView.set(values);
                        String value = CollectionUtils.join(uiView.renderToString());
                        renderValues.add(value);
                    }
                }
                return renderValues;
            } finally {
                recursionProtector.get().remove(rsKey);
            }
        }
    }

}
